/*
 * Player.cpp
 *
 *  Created on: Oct 13, 2011
 *	Created by: Devin Manno
 *  Updated by: Devin Manno, Nick James
 *	Last Update: Nov 7, 2011
 */

#include "Player.h"
#include "Utility.h"
/*
 * setupPlayer
 * Description: Populates attacks vector with all possible attacks a player can use.
 * 		Also sets unlockAttacks vector to false because these attacks havent been learned
 * Pre: none
 * Post: Character's attacks vector is full of potential moves
 * 	 based on CharClass
 * Returns: none
 */

void Player::setupPlayer()  {
	// TODO game balance, prompt player for stat allocation upon new character creation to assign playerStats
    
	// add a player's special attacks and unlocks first one
	// the following attacks are mainly place holders to test but they can be in the
	// final project if you like
	switch(characterClass){
		case WARRIOR:
			attacks.push_back(AttackType("Bash", 100, 15));	// this is element 1 in attacks vector
			attacks.push_back(AttackType("Ground Slam",150,25)); 
			attacks.push_back(AttackType("Fire Breath",170,35)); 
			attacks.push_back(AttackType("Hell Rain",250,60));
			
			// unlocks first special move
			unlockedAttacks.push_back(true);
			// set new moves to locked
            for(unsigned int i = 2; i < attacks.size(); i++)
				unlockedAttacks.push_back(false);	
			break;
		case WIZARD:
			attacks.push_back(AttackType("Fireball", 100, 15)); // this is element 1 in attacks vector
			attacks.push_back(AttackType("Abra Kadabra",150,25));
			attacks.push_back(AttackType("Lightning Ball",170,35)); 
			attacks.push_back(AttackType("Soul steal",250,60)); 
            
			// unlocks first special move
			unlockedAttacks.push_back(true);
			// set new moves to locked
			for(unsigned int i = 2; i < attacks.size(); i++)
				unlockedAttacks.push_back(false);	
			break;
		case RANGER:
			attacks.push_back(AttackType("Volley", 100, 15)); // this is element 1 in attacks vector
			attacks.push_back(AttackType("Super Shot",150,25)); 
			attacks.push_back(AttackType("Rope of Doom",170,35)); 
			attacks.push_back(AttackType("Rain of 1000 Bullets",250,60)); 
            
			// unlocks first special move
			unlockedAttacks.push_back(true);
			// set new moves to locked
            for(unsigned int i = 2; i < attacks.size(); i++)
				unlockedAttacks.push_back(false);	
			break;
	}
    
}


Player::~Player() {
	// TODO Auto-generated destructor stub
}

// getters
/*
 * getClassName
 * Description: Returns the name of the class
 * Pre: none
 * Post: none
 * Returns: a string naming the class
 */

std::string Player::getClassName() const{
	return "Player";
}
/*
 * getPlayerStats
 * Description: gets the character's stats
 * Pre: none
 * Post: none
 * Returns: the characters stats
 */
PlayerStats& Player::getPlayerStats() {
	return playerStats;
}

// setters

/*
 * pickupItem
 * Description: the player equips an item
 * Pre: item is an equippable item
 * Post: any stat bonuses provided by item are added to the player's stats.
 * 	If the player already has an item of the same type equipped, the equipped
 * 	item is dropped.
 * 	Returns: none
 */
bool Player::equip(EquipmentType* item, std::string &errorMsg){
	
	int slotNum = item->getItemType();
	
	if(equipment[slotNum] != 0)
	{
		errorMsg = "Slot not empty.  Must dequip first.";
		return false;
	}
	
	int player_agility         = playerStats.getAgility();
	int player_strength        = playerStats.getStrength();
	int player_intelligence    = playerStats.getIntelligence();
	int player_concentration   = playerStats.getConcentration();
	int player_maxActionPoints = playerStats.getMaxActionPoints();
	int player_maxHitPoints    = playerStats.getMaxHitPoints();
	int player_damage  		   = playerStats.getDamage();
	int player_armor    	   = playerStats.getArmor();
	
	int item_agility         = item->getItemStats().getAgility();
	int item_strength        = item->getItemStats().getStrength();
	int item_intelligence    = item->getItemStats().getIntelligence();
	int item_concentration   = item->getItemStats().getConcentration();
	int item_maxActionPoints = item->getItemStats().getMaxActionPoints();
	int item_maxHitPoints    = item->getItemStats().getMaxHitPoints();
	int item_damage    		 = item->getItemStats().getDamage();
	int item_armor   		 = item->getItemStats().getArmor();
	
	int new_agility         = player_agility         + item_agility;
	int new_strength        = player_strength        + item_strength;
	int new_intelligence    = player_intelligence    + item_intelligence;
	int new_concentration   = player_concentration   + item_concentration;
	int new_maxActionPoints = player_maxActionPoints + item_maxActionPoints;
	int new_maxHitPoints    = player_maxHitPoints    + item_maxHitPoints;
	int new_damage   		= player_damage    		 + item_damage;
	int new_armor    		= player_armor    		 + item_armor;
	
	playerStats.setStats(new_agility, new_strength, new_intelligence, new_concentration, new_maxActionPoints, new_maxHitPoints, new_damage, new_armor);		
	
	equipment[slotNum] = item;
	
	return true;
}

/*
 * dequip
 * Description: the player drops an item (stops using the item)
 * Pre: itemID is an objectID of an item that the player is using
 * Post: any stat bonuses provided by item are removed from the player's stats.
 * 	the player can equip a new item of "item"'s type.
 * Returns: The item the player dequipped
 */
bool Player::dequip(EquipmentType* item, std::string &errorMsg){
	
	int slotNum = item->getItemType();
	
	if(equipment[slotNum] == 0)
	{
		errorMsg = "Slot already empty.";
		return false;
	}
    
	int player_agility         = playerStats.getAgility();
	int player_strength        = playerStats.getStrength();
	int player_intelligence    = playerStats.getIntelligence();
	int player_concentration   = playerStats.getConcentration();
	int player_maxActionPoints = playerStats.getMaxActionPoints();
	int player_maxHitPoints    = playerStats.getMaxHitPoints();
	int player_damage  		   = playerStats.getDamage();
	int player_armor    	   = playerStats.getArmor();
	
	int item_agility         = item->getItemStats().getAgility();
	int item_strength        = item->getItemStats().getStrength();
	int item_intelligence    = item->getItemStats().getIntelligence();
	int item_concentration   = item->getItemStats().getConcentration();
	int item_maxActionPoints = item->getItemStats().getMaxActionPoints();
	int item_maxHitPoints    = item->getItemStats().getMaxHitPoints();
	int item_damage    		 = item->getItemStats().getDamage();
	int item_armor   		 = item->getItemStats().getArmor();
	
	int new_agility         = player_agility         - item_agility;
	int new_strength        = player_strength        - item_strength;
	int new_intelligence    = player_intelligence    - item_intelligence;
	int new_concentration   = player_concentration   - item_concentration;
	int new_maxActionPoints = player_maxActionPoints - item_maxActionPoints;
	int new_maxHitPoints    = player_maxHitPoints    - item_maxHitPoints;
	int new_damage   		= player_damage    		 - item_damage;
	int new_armor    		= player_armor    		 - item_armor;
	
	playerStats.setStats(new_agility, new_strength, new_intelligence, new_concentration, new_maxActionPoints, new_maxHitPoints, new_damage, new_armor);		
	
	equipment[slotNum] = 0;     // set to NULL
	
	return true;
}

/*
 * usePotion
 * Description: Player uses a health potion to restore the player's health
 * Pre: Player has a health potion
 * Post: Player's health is increased by 75% of max
 * Returns: a string describing the effect of using the health potion
 */
bool Player::usePotion(Potion *potion){
	float hpp = potion->getHitPointPercentage();
	float app = potion->getActionPointPercentage();
    
	// add hit points if potion contains a buff to hit points
	int maxhp = playerStats.getMaxHitPoints();	// current max hit points
	int curhp = playerStats.getHitPoints();		// current hit points
	int addhp = maxhp * hpp;			// hit points to add to player's current hit points
    
	if((addhp + curhp) > maxhp)
        playerStats.setHitPoints(maxhp);
    else
        playerStats.setHitPoints(addhp + curhp);
    
	// add action points if potion contains a buff to action points
	int maxap = playerStats.getMaxActionPoints();	// current max action points
	int curap = playerStats.getActionPoints();	// current action points
	int addap = maxap * app;			// action points to add to a player's current action points
    
	if((addap + curap) > maxap)
		playerStats.setActionPoints(maxap);
	else
		playerStats.setActionPoints(addap + curap);
    
	return true;   					//controller should delete potion pointer on success.
}

/*
 * regenerateHP
 * Description: Increases players hitpoints by 5 everytime called 
 * Pre: none
 * Post: Player's hit points boosted by 5 up to max
 * Returns: none
 */
void Player::regenerateHP(){
	int fivePercentofMaxHP = playerStats.getMaxHitPoints() / 20;
	playerStats.increaseHitPoints(fivePercentofMaxHP);
}


/*
 * regenerateAP
 * Description: Increases players action points by 5 everytime called 
 * Pre: none
 * Post: Player's action points boosted by 5 up to max
 * Returns: none
 */
void Player::regenerateAP(){
	int fivePercentofMaxAP = playerStats.getMaxActionPoints() / 20;
	playerStats.increaseActionPoints(fivePercentofMaxAP);
}

/*
 * increaseExp
 * Description: Increases players experience points and level
 * Pre: Player has a x amount of experience points
 * Post: Player's experience points boosted by boost amoung
 * Returns: bool that indicates whether or not new abilities were unlocked
 */

bool Player::increaseExp(int boost){
	int exp = playerStats.getExp();
	int newExp = exp + boost;
	int curLevel = playerStats.getLevel();
	int newLevel = newExp / XPFULL;	// used to find new level. XPFULL is set in h file
	
	playerStats.setExp(newExp);
	
	// call level up only if necessary
	if(newLevel > curLevel){
		playerStats.setLevel(newLevel);	
		return levelUp();
	}
	else
		return false;
}

/*
 * levelUp
 * Description: unlocks new abilites for player and auto boost stats
 * Pre: takes level of player to determine if unlocked anything
 * Post: If players experience reaches certain level,
 * 	they unlock a new ability
 * Returns: bool that indicates whether or not new abilities were unlocked
 */
bool Player::levelUp(){
	bool flag = false;	// indicates whether or not something has been unlocked
	int curLevel = playerStats.getLevel();
    
	/*
     // increment max health and max action points and
     // 	give player max health and AP as an added bonus for leveling up
     playerStats.setMaxActionPoints(playerStats.getMaxActionPoints() + 10);
     playerStats.setActionPoints(playerStats.getMaxActionPoints());
     playerStats.setMaxHitPoints(playerStats.getMaxHitPoints() + 10);
     playerStats.setHitPoints(playerStats.getMaxHitPoints());
     */
	// check and see if unlocked new attack
	// and increase stats
	if(curLevel >= UNLOCK4){
		boostStats(UNLOCK4);
	}
	else if(curLevel >= UNLOCK3){
		boostStats(UNLOCK3);
	}
	else if(curLevel >= UNLOCK2){
		unlockAttack(3);	// unlock last attack
		boostStats(UNLOCK2);
		flag = true;
	}
	else if(curLevel >= UNLOCK1){
		unlockAttack(2);	// unlock 3rd attack
		boostStats(UNLOCK1);
		flag = true;
	}
	else{
		boostStats(DEFAULT);
	}
	return flag;
}

// need to change how it changes stats
void Player::boostStats(unlockLevels level){
	
    short addTo = 0;
	int total = playerStats.getAgility() + playerStats.getStrength() + playerStats.getIntelligence() + playerStats.getConcentration();
	int boost = 0;
	// boost stats faster in lower levels
	if(level >= UNLOCK4)
		boost = 3;
	else if(level >= UNLOCK3)
		boost = 4;
	else if(level >= UNLOCK2)
		boost = 7;
	else
		boost = 7;
	boost += total;
	// boost stats according to characterClass
    switch(characterClass) {
        case WARRIOR:
            while((playerStats.getAgility() + playerStats.getStrength() + playerStats.getIntelligence() + playerStats.getConcentration()) < boost){
                addTo = Utility::getSeed(6 + 1);         // random 1-6
                if(addTo == 1)
                    playerStats.setAgility(playerStats.getAgility()+1);
                else if(addTo == 2)
                    playerStats.setStrength(playerStats.getStrength()+1);
                else if(addTo == 3)
                    playerStats.setIntelligence(playerStats.getIntelligence()+1);
                else if(addTo == 4)
                    playerStats.setConcentration(playerStats.getConcentration()+1);
                else // 2/5 chance to increase strength
                    playerStats.setStrength(playerStats.getStrength()+1);
            }
            break;
        case WIZARD:
            while((playerStats.getAgility() + playerStats.getStrength() + playerStats.getIntelligence() + playerStats.getConcentration()) < boost){
                addTo = Utility::getSeed(6 + 1);         // random 1-6
                if(addTo == 1)
                    playerStats.setAgility(playerStats.getAgility()+1);
                else if(addTo == 2)
                    playerStats.setStrength(playerStats.getStrength()+1);
                else if(addTo == 3)
                    playerStats.setIntelligence(playerStats.getIntelligence()+1);
                else if(addTo == 4)
                    playerStats.setConcentration(playerStats.getConcentration()+1);
                else // 2/5 chance to increase strength
                    playerStats.setIntelligence(playerStats.getIntelligence()+1);
            }
            break;
        case RANGER:
            while((playerStats.getAgility() + playerStats.getStrength() + playerStats.getIntelligence() + playerStats.getConcentration()) < boost){
                addTo = Utility::getSeed(6 + 1);         // random 1-6
                if(addTo == 1)
                    playerStats.setAgility(playerStats.getAgility()+1);
                else if(addTo == 2)
                    playerStats.setStrength(playerStats.getStrength()+1);
                else if(addTo == 3)
                    playerStats.setIntelligence(playerStats.getIntelligence()+1);
                else if(addTo == 4)
                    playerStats.setConcentration(playerStats.getConcentration()+1);
                else // 2/5 chance to increase strength
                    playerStats.setConcentration(playerStats.getConcentration()+1);
            }
            break;
        default: // should not happen but wont increment anything is it does
            break;
    }
    
}
